/***************************************************************************
 *   Copyright (C) 2008 by Milambert									   *
 *   nexus6b@gmail.com   												   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "config.h"
#include "common.h"
#include "confHandler.h"
#include "mysqlHandler.h"
#include "cardReader.h"

int main(int argc, char *argv[]) {
	struct sockaddr_in remoteAddr;
	struct timeval tv;
	socklen_t remoteLen;
	fd_set master, readfds;
	time_t startTime;
	int auth, servSock;
	int fdmax, i, j;
	int dataLenTmp, nbBytes;	
	char buffer[MAXBUFLEN], str[MAXBUFLEN];	
	char ipAddTmp[5], localTmp[5], cmdTmp, dataTmp[255];
	
#ifdef DEBUG
	printf("debug OK\n");
	printf("log: %s\n", LOG_FILE);
	printf("run: %s\n", RUN_DIR);
	printf("lock: %s\n", LOCK_FILE);
	printf("conf: %s\n", CONF_FILE);
#endif
	
	//init some default config
	sockPort = 0;
	myPort = 0;
	timer = 10;		//by delault probe each 10 sec
	
	writeLog("\nDEBUT");
	// Read config
	//------------
	if(argc > 1)
		readArg(argc, argv);

	readConfFile();
	
#ifdef DEBUG
	printf("socket port: %i\n", sockPort);
	printf("MySQL port:  %i\n", myPort);
	printf("MySQL user:  %s\n", myUser);
	printf("MySQL pwd:   %s\n", myPwd);
	printf("MySQL host:  %s\n", myHost);
	printf("MySQL DB:    %s\n", myDB);
	printf("timer:       %f\n", timer);
	printf("version:     %s\n\n", OTFDD_VERSION);
#endif

#ifdef DEBUG
	printf("we are in debug mode\n");
#else
	initServer();
#endif
	
	writeLog("II:	Server Start normaly");
	
	//init MySQL
	//----------
	mysqlInit();
	
	//init udp socket
	//---------------
	
	//clear file descriptors list
	FD_ZERO(&master);
	FD_ZERO(&readfds);
	
	servSock = initSocket();	
	
	//add servSock to the master list
	FD_SET(servSock, &master);
	
	fdmax = servSock;

	memset(str, 0, sizeof(str));
	
	//start timer
	startTime = time(NULL);
	
	while(1){
		//clear buffer
		memset(buffer, 0, sizeof(buffer));
		
		//set select timeout
		tv.tv_sec = 2;
		tv.tv_usec = 0;
		
		//copy master list to readfds list
		readfds = master;
		
		if(select(fdmax + 1, &readfds, NULL, NULL, &tv) == -1){
			writeLog("EE:	echec select");
			exit(EXIT_FAILURE);
		}
		
		if(FD_ISSET(servSock, &readfds)){
			if((nbBytes = recvfrom(servSock, buffer, sizeof(buffer), 0, 
									(struct sockaddr *)&remoteAddr, &remoteLen)) == -1){
					writeLog("EE:	echec read newSockfd");
					exit(EXIT_FAILURE);
				}		
#ifdef DEBUG
			printf("got packet on %d\n", servSock);
			printf("    from %s\n", inet_ntoa(remoteAddr.sin_addr));
			printf("    with %s\n", buffer);
#endif
			if(nbBytes == 0){
				sprintf(str, "WW:	connection %d @ %s lost",
						servSock, inet_ntoa(remoteAddr.sin_addr));		
				writeLog(str);
			}
			else{
				memset(ipAddTmp, 0, sizeof(ipAddTmp));
				memset(localTmp, 0, sizeof(localTmp));
				memset(dataTmp, 0, sizeof(dataTmp));
				
				for(i = 0; i < 4; i++){
					ipAddTmp[i] = buffer[i];
				}
										
				for(i = 4, j = 0; j < 3; i++, j++){
					localTmp[j] = buffer[i];
				}
										
				cmdTmp = buffer[7];
				dataLenTmp = buffer[8];
				
				for(i = 9, j = 0; j < dataLenTmp && buffer[i] != '\n'; i++, j++){
					dataTmp[j] = buffer[i];
				}

#ifdef DEBUG
				printf("data :\n");
				printf("    ip:       %s\n", ipAddTmp);
				printf("    local:    %d\n", atoi(localTmp));
				printf("    cmd:      %c\n", cmdTmp);
				printf("    data len: %d\n", dataLenTmp);
				printf("    data:     %s\n", dataTmp);
				
				if(strcmp(buffer, "zzz") == 0){
					printf("got end command\n");
					break;
				}
#endif
				//test for wrong local => go to defaut switch action
				if(strcmp(localTmp, "000") == 0)
					cmdTmp = 'E';
				
				switch(cmdTmp){
					case FIRST_C:
						addCardReader(atoi(localTmp), inet_ntoa(remoteAddr.sin_addr));
						
						//set reply
						memset(str, 0, sizeof(str));
						sprintf(str, "0000000%c%dOK", CONN_AS, 3);
#ifdef DEBUG						
						printf("first: %s\n", str);
#endif						
						//send reply
						if ((nbBytes = sendto(servSock, str, (strlen(str) + 1), 0,
									(struct sockaddr *)&remoteAddr, sizeof(remoteAddr))) == -1){
							char strErr[50];
							sprintf(strErr, "EE:	sendto %s failed", inet_ntoa(remoteAddr.sin_addr));
							writeLog(strErr);
							//exit(EXIT_FAILURE);
						}
						
						break;
						
					case CONN_RQ:
						updateCardReader(atoi(localTmp), 0, inet_ntoa(remoteAddr.sin_addr), "OK", 0);
						
						//set reply
						memset(str, 0, sizeof(str));
						sprintf(str, "0000000%c%dOK", CONN_AS, 3);
#ifdef DEBUG						
						printf("conn: %s\n", str);
#endif						
						//send reply
						if ((nbBytes = sendto(servSock, str, (strlen(str) + 1), 0,
									(struct sockaddr *)&remoteAddr, sizeof(remoteAddr))) == -1){
							char strErr[50];
							sprintf(strErr, "EE:	sendto %s failed", inet_ntoa(remoteAddr.sin_addr));
							writeLog(strErr);
							//exit(EXIT_FAILURE);
						}
						break;
						
					case AUTH_RQ:
						//Authentification request
						auth = requestAuth(atoi(localTmp), dataTmp);
						
						//set reply
						memset(str, 0, sizeof(str));
						if(auth)
							sprintf(str, "0000000%c%dOK", AUTH_AS, 3);
						else
							sprintf(str, "0000000%c%dNO", AUTH_AS, 3);
#ifdef DEBUG						
						printf("auth: %s\n", str);
#endif						
						//send reply
						if ((nbBytes = sendto(servSock, str, (strlen(str) + 1), 0,
									(struct sockaddr *)&remoteAddr, sizeof(remoteAddr))) == -1){
							char strErr[50];
							sprintf(strErr, "EE:	sendto %s failed", inet_ntoa(remoteAddr.sin_addr));
							writeLog(strErr);
							//exit(EXIT_FAILURE);
						}
						break;
						
					default:
						sprintf(str, "II:	wrong command by %s", inet_ntoa(remoteAddr.sin_addr));
						writeLog(str);

						memset(str, 0, sizeof(str));
						sprintf(str, "0000000%c%d0",ERROR, 2);
#ifdef DEBUG						
						printf("auth: %s\n", str);
#endif						
						if ((nbBytes = sendto(servSock, str, (strlen(str) - 1), 0,
									(struct sockaddr *)&remoteAddr, sizeof(remoteAddr))) == -1){
							char strErr[50];
							sprintf(strErr, "EE:	sendto %s failed", inet_ntoa(remoteAddr.sin_addr));
							writeLog(strErr);
							//exit(EXIT_FAILURE);
						}

						break;
				}
			}			
		}
		
		if(difftime(time(NULL), startTime) >= timer){
#ifdef DEBUG
			printf("now check all card Reader\n");
#endif
			checkCardReader();
			startTime = time(NULL);
		}
	}
	
	closeMysql();

	writeLog("II:	Server Stop normaly\nFIN");
	
	flushMem();
	return EXIT_SUCCESS;
}
